using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DL;
using UnityEngine;
using YooAsset;

public class Init : MonoBehaviour
{
    /// <summary>
    /// 运行模式
    /// </summary>
    public EPlayMode PlayMode;

    ResourcePackage package;

    // Start is called before the first frame update
    void Start()
    {
        // 初始化资源系统
        // YooAssets.Initialize();
        //
        // // 创建默认的资源包
        // package = YooAssets.CreatePackage("DefaultPackage");
        //
        // // 设置该资源包为默认的资源包，可以使用YooAssets相关加载接口加载该资源包内容。
        // YooAssets.SetDefaultPackage(package);

         _ = Load.Inst;
        
        StartCoroutine(InitializeYooAsset());
    }

    private IEnumerator InitializeYooAsset()
    {
#if !UNITY_EDITOR
        PlayMode = EPlayMode.HostPlayMode;
#endif
        if (PlayMode == EPlayMode.HostPlayMode)
        {
            string defaultHostServer = GetHostServerURL();
            string fallbackHostServer = GetHostServerURL();
            var initParameters = new HostPlayModeParameters();
            initParameters.BuildinQueryServices = new GameQueryServices();
            initParameters.DecryptionServices = null;
            initParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
            var initOperation = package.InitializeAsync(initParameters);
            yield return initOperation;

            if (initOperation.Status == EOperationStatus.Succeed)
            {
                Debug.Log("资源包初始化成功！");
                StartCoroutine(UpdatePackageVersion());
            }
            else
            {
                Debug.LogError($"资源包初始化失败：{initOperation.Error}");
            }
        }
        else
        {
            var initParameters = new EditorSimulateModeParameters();
            initParameters.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild("BuiltinBuildPipeline", "DefaultPackage");
            yield return package.InitializeAsync(initParameters);
            //更新代码
            StartCoroutine(RunHofixDllInit());
        }

    }

    /// <summary>
    /// 获取资源服务器地址
    /// </summary>
    private string GetHostServerURL()
    {
        string headResPath = "https://127.0.0.1/HybridCLR";
        string gameResVersion = GameConfigApp.GameResVersion;

#if UNITY_EDITOR
        if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)
            return $"{headResPath}/Android/{gameResVersion}";
        else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)
            return $"{headResPath}/IPhone/{gameResVersion}";
        else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)
            return $"{headResPath}/WebGL/{gameResVersion}";
        else
            return $"{headResPath}/PC/{gameResVersion}";
#else
        if (Application.platform == RuntimePlatform.Android)
            return $"{headResPath}/Android/{gameResVersion}";
        else if (Application.platform == RuntimePlatform.IPhonePlayer)
            return $"{headResPath}/IPhone/{gameResVersion}";
        else if (Application.platform == RuntimePlatform.WebGLPlayer)
            return $"{headResPath}/WebGL/{gameResVersion}";
        else
            return $"{headResPath}/PC/{gameResVersion}";
#endif
    }

    //获取资源版本
    private IEnumerator UpdatePackageVersion()
    {
        var package = YooAssets.GetPackage("DefaultPackage");
        var operation = package.UpdatePackageVersionAsync();
        yield return operation;

        if (operation.Status == EOperationStatus.Succeed)
        {
            //更新成功
            string packageVersion = operation.PackageVersion;
            StartCoroutine(UpdatePackageManifest(packageVersion));
            Debug.Log($"Updated package Version : {packageVersion}");
        }
        else
        {
            //更新失败
            Debug.LogError(operation.Error);
        }
    }

    //更新资源清单
    private IEnumerator UpdatePackageManifest(string packageVersion)
    {
        // 更新成功后自动保存版本号，作为下次初始化的版本。
        // 也可以通过operation.SavePackageVersion()方法保存。
        bool savePackageVersion = true;
        var package = YooAssets.GetPackage("DefaultPackage");
        var operation = package.UpdatePackageManifestAsync(packageVersion, savePackageVersion);
        yield return operation;

        if (operation.Status == EOperationStatus.Succeed)
        {
            //更新成功
            StartCoroutine(Download());
        }
        else
        {
            //更新失败
            Debug.LogError(operation.Error);
        }
    }

    IEnumerator Download()
    {
        int downloadingMaxNum = 10;
        int failedTryAgain = 3;
        var package = YooAssets.GetPackage("DefaultPackage");
        var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);

        //没有需要下载的资源
        if (downloader.TotalDownloadCount == 0)
        {
            StartCoroutine(RunHofixDllInit());
            yield break;
        }

        //需要下载的文件总数和总大小
        int totalDownloadCount = downloader.TotalDownloadCount;
        long totalDownloadBytes = downloader.TotalDownloadBytes;

        //注册回调方法
        downloader.OnDownloadErrorCallback = OnDownloadErrorFunction;
        downloader.OnDownloadProgressCallback = OnDownloadProgressUpdateFunction;
        downloader.OnDownloadOverCallback = OnDownloadOverFunction;
        downloader.OnStartDownloadFileCallback = OnStartDownloadFileFunction;

        //开启下载
        downloader.BeginDownload();
        yield return downloader;

        //检测下载结果
        if (downloader.Status == EOperationStatus.Succeed)
        {
            //下载成功
            StartCoroutine(RunHofixDllInit());
        }
        else
        {
            //下载失败
        }
    }

    private void OnStartDownloadFileFunction(string fileName, long sizeBytes)
    {
        Debug.Log($"加载资源{fileName}，大小{sizeBytes}bytes");
    }
    
    private void OnDownloadOverFunction(bool isSucceed)
    {
        Debug.Log("加载资源" + (isSucceed ? "成功" : "失败"));
    }

    private void OnDownloadProgressUpdateFunction(int totalDownloadCount, int currentDownloadCount,
        long totalDownloadBytes, long currentDownloadBytes)
    {
        Debug.Log(
            $"加载资源数量{totalDownloadCount},当前加载{currentDownloadCount}。加载资源总大小{totalDownloadBytes}bytes,当前加载{currentDownloadBytes}bytes。");
    }

    private void OnDownloadErrorFunction(string fileName, string error)
    {
        Debug.Log($"加载资源{fileName}失败，error{error}");
    }

    IEnumerator RunHofixDllInit()
    {
        var package = YooAssets.GetPackage("DefaultPackage");

        List<TextAsset> aotDllList = new List<TextAsset>();
        for (int i = 0; i < GameConfigApp.AotDllNameList.Count; i++)
        {
            AssetHandle metadataCodehandle = package.LoadAssetAsync<TextAsset>("MetaDataDll_" + GameConfigApp.AotDllNameList[i]);
            yield return metadataCodehandle;
            TextAsset metadatacodeobj = metadataCodehandle.AssetObject as TextAsset;
            aotDllList.Add(metadatacodeobj);
        }
        // 先补充元数据
        LoadMetadataForAOTAssemblies(aotDllList);


#if !UNITY_EDITOR
        AssetHandle codehandle = package.LoadAssetAsync<TextAsset>("Code_Unity.Hotfix.dll");
        yield return codehandle;
        TextAsset codeobj = codehandle.AssetObject as TextAsset;
        byte[] codeBytes = codeobj.bytes;

        // Editor环境下，HotUpdate.dll.bytes已经被自动加载，不需要加载，重复加载反而会出问题。
        Assembly hotUpdateAss = Assembly.Load(codeBytes);
#else
        // Editor下无需加载，直接查找获得HotUpdate程序集
        Assembly hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "DL.Hotfix");
#endif

        Type type = hotUpdateAss.GetType("HotfixMain");
        type.GetMethod("Run").Invoke(null, null);
        yield return null;
    }

    private static void LoadMetadataForAOTAssemblies(List<TextAsset> aotDllList)
    {
        foreach (var aotDll in aotDllList)
        {
            byte[] dllBytes = aotDll.bytes;
            LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);
            Debug.Log($"LoadMetadataForAOTAssembly:{aotDll.name}. ret:{err}");
        }
    }



    /// <summary>
    /// 远端资源地址查询服务类
    /// </summary>
    private class RemoteServices : IRemoteServices
    {
        private readonly string _defaultHostServer;
        private readonly string _fallbackHostServer;

        public RemoteServices(string defaultHostServer, string fallbackHostServer)
        {
            _defaultHostServer = defaultHostServer;
            _fallbackHostServer = fallbackHostServer;
        }
        string IRemoteServices.GetRemoteMainURL(string fileName)
        {
            return $"{_defaultHostServer}/{fileName}";
        }
        string IRemoteServices.GetRemoteFallbackURL(string fileName)
        {
            return $"{_fallbackHostServer}/{fileName}";
        }
    }
}